import React from 'react';
import PropTypes from 'prop-types';

class WaveProgress extends React.Component {
  componentDidMount() {
    if (this.canvas) {
      const ctx = this.canvas.getContext('2d');
      this.drawWave(ctx);
    }
  }

  /* eslint-disable no-undef */
  /* eslint-disable no-param-reassign */
  drawWave = (ctx) => {
    // 默认颜色
    const defaultColor = '#108EE9';

    const { width, height } = this.canvas;

    // 波宽
    const waveWidth = width;

    // 波峰 是高度的 1/10
    const waveCrest = height / 10;

    // 波浪定位高度
    const wavePos = height * (1 - ((this.props.progress || 50) / 100));

    // 获取 贝塞尔 四个控制点, 起点, 波峰(谷)点, 波谷(峰)点, 终点
    const getWaveCtrl = (x, y) => {
      const start = { x, y };
      const end = { x: x + waveWidth + 2, y }; // 2 用来消除边线
      const ctrl1 = {
        x: x + (waveWidth / 2),
        y: y - (waveCrest * 1.5),
      };

      const ctrl2 = {
        x: x + ((waveWidth * 1) / 2),
        y: y + (waveCrest * 1.5),
      };

      return { start, ctrl1, ctrl2, end };
    };

    // 文本
    const drawText = () => {
      const subFontSize = (this.props.fontSize || '48px').replace(/[^\d]+/, '') / 4;
      const text = this.props.text || `${this.props.progress}%`;

      ctx.save();
      ctx.globalCompositeOperation = 'xor';
      ctx.fillStyle = this.props.textColor || defaultColor;
      ctx.font = `${this.props.fontSize || '48px'} arial`;
      ctx.textAlign = 'center';
      ctx.fillText(text, width / 2, (height / 2) + subFontSize);
    };

    const requestAnimFrame = window.requestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      (cb => window.setTimeout(cb, 1000 / 60));

    let walk = 0;
    const step = this.props.step || (width / 60);

    const loop = () => {
      ctx.clearRect(0, 0, width, height);
      ctx.globalCompositeOperation = 'source-over';

      ctx.fillStyle = this.props.waveColor || defaultColor;

      // 三条波浪 - 平移, 以形成波浪视觉
      [1, 0, -1].forEach((i) => {
        const dev = i * waveWidth;

        const { start, ctrl1, ctrl2, end } = getWaveCtrl(walk + dev, wavePos);
        ctx.beginPath();
        ctx.moveTo(start.x, start.y);
        ctx.bezierCurveTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y);

        // 需要绘制的其余的点, 以组成封闭的图形
        ctx.lineTo(end.x, height);
        ctx.lineTo(start.x, height);
        ctx.lineTo(start.x, start.y);
        ctx.closePath();
        ctx.fill();
      });

      walk += step;

      if (walk >= waveWidth) {
        walk = 0;
      }

      if (this.props.text !== false) {
        drawText();
      }

      if (this.props.motion !== false) {
        requestAnimFrame(loop);
      }
    };

    loop();
  }

  render() {
    const circle = { borderRadius: '50%' };
    const { className, style = {} } = this.props;

    const finalStyle = !style.borderRadius ? { ...style, ...circle } : style;

    const resetWidth = this.props.width || (style || {}).width;
    const resetHeight = this.props.height || (style || {}).height;

    return (
      <canvas
        width={resetWidth}
        height={resetHeight}
        className={className}
        style={finalStyle}
        ref={x => (this.canvas = x)}
      />
    );
  }
}

WaveProgress.propTypes = {
  progress: PropTypes.number,
  text: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
  motion: PropTypes.bool,
  step: PropTypes.number,
  className: PropTypes.string,
  style: PropTypes.object,
  width: PropTypes.string,
  height: PropTypes.string,
  fontSize: PropTypes.string,
  textColor: PropTypes.string,
  waveColor: PropTypes.string,
};

export default WaveProgress;
